summaryrefslogtreecommitdiff
path: root/src/app
diff options
context:
space:
mode:
Diffstat (limited to 'src/app')
-rw-r--r--src/app/(payload)/admin/[[...segments]]/not-found.tsx23
-rw-r--r--src/app/(payload)/admin/[[...segments]]/page.tsx23
-rw-r--r--src/app/(payload)/admin/importMap.js3
-rw-r--r--src/app/(payload)/api/[...slug]/route.ts19
-rw-r--r--src/app/(payload)/custom.scss1
-rw-r--r--src/app/(payload)/layout.tsx31
-rw-r--r--src/app/(public)/about/page.tsx153
-rw-r--r--src/app/(public)/articles/page.tsx38
-rw-r--r--src/app/(public)/demos/page.tsx94
-rw-r--r--src/app/(public)/layout.tsx16
-rw-r--r--src/app/(public)/page.tsx174
-rw-r--r--src/app/(public)/services/page.tsx148
-rw-r--r--src/app/globals.css102
-rw-r--r--src/app/layout.tsx31
14 files changed, 856 insertions, 0 deletions
diff --git a/src/app/(payload)/admin/[[...segments]]/not-found.tsx b/src/app/(payload)/admin/[[...segments]]/not-found.tsx
new file mode 100644
index 0000000..62ffef8
--- /dev/null
+++ b/src/app/(payload)/admin/[[...segments]]/not-found.tsx
@@ -0,0 +1,23 @@
+/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
+/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
+import type { Metadata } from "next";
+
+import config from "@payload-config";
+import { NotFoundPage, generatePageMetadata } from "@payloadcms/next/views";
+import { importMap } from "../importMap";
+
+type Args = {
+ params: Promise<{ segments: string[] }>;
+ searchParams: Promise<{ [key: string]: string | string[] }>;
+};
+
+export const generateMetadata = ({
+ params,
+ searchParams,
+}: Args): Promise<Metadata> =>
+ generatePageMetadata({ config, params, searchParams });
+
+const NotFound = ({ params, searchParams }: Args) =>
+ NotFoundPage({ config, importMap, params, searchParams });
+
+export default NotFound;
diff --git a/src/app/(payload)/admin/[[...segments]]/page.tsx b/src/app/(payload)/admin/[[...segments]]/page.tsx
new file mode 100644
index 0000000..3132b87
--- /dev/null
+++ b/src/app/(payload)/admin/[[...segments]]/page.tsx
@@ -0,0 +1,23 @@
+/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
+/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
+import type { Metadata } from "next";
+
+import config from "@payload-config";
+import { RootPage, generatePageMetadata } from "@payloadcms/next/views";
+import { importMap } from "../importMap";
+
+type Args = {
+ params: Promise<{ segments: string[] }>;
+ searchParams: Promise<{ [key: string]: string | string[] }>;
+};
+
+export const generateMetadata = ({
+ params,
+ searchParams,
+}: Args): Promise<Metadata> =>
+ generatePageMetadata({ config, params, searchParams });
+
+const Page = ({ params, searchParams }: Args) =>
+ RootPage({ config, params, searchParams, importMap });
+
+export default Page;
diff --git a/src/app/(payload)/admin/importMap.js b/src/app/(payload)/admin/importMap.js
new file mode 100644
index 0000000..6b29107
--- /dev/null
+++ b/src/app/(payload)/admin/importMap.js
@@ -0,0 +1,3 @@
+/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
+/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
+export const importMap = {};
diff --git a/src/app/(payload)/api/[...slug]/route.ts b/src/app/(payload)/api/[...slug]/route.ts
new file mode 100644
index 0000000..dc8ba37
--- /dev/null
+++ b/src/app/(payload)/api/[...slug]/route.ts
@@ -0,0 +1,19 @@
+/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
+/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
+import config from "@payload-config";
+import "@payloadcms/next/css";
+import {
+ REST_DELETE,
+ REST_GET,
+ REST_OPTIONS,
+ REST_PATCH,
+ REST_POST,
+ REST_PUT,
+} from "@payloadcms/next/routes";
+
+export const GET = REST_GET(config);
+export const POST = REST_POST(config);
+export const DELETE = REST_DELETE(config);
+export const PATCH = REST_PATCH(config);
+export const PUT = REST_PUT(config);
+export const OPTIONS = REST_OPTIONS(config);
diff --git a/src/app/(payload)/custom.scss b/src/app/(payload)/custom.scss
new file mode 100644
index 0000000..a8d95bd
--- /dev/null
+++ b/src/app/(payload)/custom.scss
@@ -0,0 +1 @@
+/* Custom styles for the Payload admin panel - can be extended later */
diff --git a/src/app/(payload)/layout.tsx b/src/app/(payload)/layout.tsx
new file mode 100644
index 0000000..3c6b6e4
--- /dev/null
+++ b/src/app/(payload)/layout.tsx
@@ -0,0 +1,31 @@
+/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
+/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
+import config from "@payload-config";
+import "@payloadcms/next/css";
+import type { ServerFunctionClient } from "payload";
+import { handleServerFunctions, RootLayout } from "@payloadcms/next/layouts";
+import React from "react";
+
+import { importMap } from "./admin/importMap.js";
+import "./custom.scss";
+
+type Args = {
+ children: React.ReactNode;
+};
+
+const serverFunction: ServerFunctionClient = async function (args) {
+ "use server";
+ return handleServerFunctions({
+ ...args,
+ config,
+ importMap,
+ });
+};
+
+const Layout = ({ children }: Args) => (
+ <RootLayout config={config} importMap={importMap} serverFunction={serverFunction}>
+ {children}
+ </RootLayout>
+);
+
+export default Layout;
diff --git a/src/app/(public)/about/page.tsx b/src/app/(public)/about/page.tsx
new file mode 100644
index 0000000..7e76cbe
--- /dev/null
+++ b/src/app/(public)/about/page.tsx
@@ -0,0 +1,153 @@
+import { Code, Server, Shield, Award } from "lucide-react";
+
+const timeline = [
+ {
+ icon: Code,
+ period: "Début de carrière",
+ title: "Développeur",
+ description:
+ "Développement logiciel, compréhension profonde du code et des architectures applicatives. Base solide pour comprendre les enjeux de sécurité au niveau applicatif.",
+ },
+ {
+ icon: Server,
+ period: "Évolution",
+ title: "Administrateur Systèmes",
+ description:
+ "Administration Linux et Windows Server. Gestion d'infrastructures, scripting, automatisation. Vision complète de la chaîne technique.",
+ },
+ {
+ icon: Shield,
+ period: "Spécialisation",
+ title: "Expert IAM & Sécurité",
+ description:
+ "Spécialisation en Identity & Access Management. Administration AD et Entra ID, implémentation OIDC/OAuth, stratégies Zero Trust.",
+ },
+];
+
+const skills = {
+ "Identity & Access Management": [
+ "OIDC / OAuth 2.0 / SAML",
+ "Keycloak",
+ "Active Directory",
+ "Microsoft Entra ID (Azure AD)",
+ "PIM / PAM",
+ "RBAC / ABAC",
+ "Conditional Access",
+ "SSO / Federation",
+ ],
+ "Sécurité": [
+ "Zero Trust Architecture",
+ "Durcissement AD (Tiering Model)",
+ "Sécurité des endpoints",
+ "PKI & Certificats",
+ "Audit de sécurité",
+ "Conformité & Gouvernance",
+ ],
+ "Systèmes & Infra": [
+ "Windows Server / AD DS",
+ "Linux (Debian, RHEL, Ubuntu)",
+ "Docker & Conteneurisation",
+ "PowerShell / Bash",
+ "Automatisation & CI/CD",
+ "Monitoring & Logging",
+ ],
+};
+
+export default function AboutPage() {
+ return (
+ <>
+ <section className="bg-cosmos-900 py-16 sm:py-20">
+ <div className="mx-auto max-w-7xl px-6 lg:px-8">
+ <div className="mx-auto max-w-2xl text-center">
+ <h1 className="text-3xl font-bold tracking-tight text-nieve sm:text-5xl">
+ À propos
+ </h1>
+ <p className="mt-6 text-lg text-cosmos-300">
+ Un parcours du développement à la sécurité, pour une vision
+ complète et pragmatique de l&apos;IAM.
+ </p>
+ </div>
+ </div>
+ </section>
+
+ {/* Timeline */}
+ <section className="py-20">
+ <div className="mx-auto max-w-7xl px-6 lg:px-8">
+ <h2 className="text-2xl font-bold text-cosmos-900 text-center mb-16">
+ Parcours professionnel
+ </h2>
+ <div className="relative">
+ <div className="absolute left-1/2 -translate-x-px h-full w-0.5 bg-border hidden lg:block" />
+ <div className="space-y-12 lg:space-y-16">
+ {timeline.map((item, index) => {
+ const Icon = item.icon;
+ const isLeft = index % 2 === 0;
+ return (
+ <div
+ key={item.title}
+ className={`relative flex flex-col lg:flex-row items-center gap-8 ${
+ isLeft ? "lg:flex-row" : "lg:flex-row-reverse"
+ }`}
+ >
+ <div
+ className={`flex-1 ${isLeft ? "lg:text-right" : "lg:text-left"}`}
+ >
+ <p className="text-sm font-semibold text-araucaria-600 uppercase tracking-wider">
+ {item.period}
+ </p>
+ <h3 className="mt-2 text-xl font-bold text-cosmos-900">
+ {item.title}
+ </h3>
+ <p className="mt-3 text-muted leading-relaxed">
+ {item.description}
+ </p>
+ </div>
+ <div className="relative z-10 w-14 h-14 rounded-full bg-cosmos-900 flex items-center justify-center border-4 border-nieve shadow-lg shrink-0">
+ <Icon className="w-6 h-6 text-araucaria-400" />
+ </div>
+ <div className="flex-1 hidden lg:block" />
+ </div>
+ );
+ })}
+ </div>
+ </div>
+ </div>
+ </section>
+
+ {/* Compétences */}
+ <section className="py-20 bg-pewma border-t border-border">
+ <div className="mx-auto max-w-7xl px-6 lg:px-8">
+ <h2 className="text-2xl font-bold text-cosmos-900 text-center mb-16">
+ Compétences techniques
+ </h2>
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-8">
+ {Object.entries(skills).map(([category, items]) => (
+ <div
+ key={category}
+ className="rounded-xl border border-border bg-nieve p-8"
+ >
+ <div className="flex items-center gap-3 mb-6">
+ <Award className="w-5 h-5 text-kultrun-700" />
+ <h3 className="text-lg font-semibold text-cosmos-900">
+ {category}
+ </h3>
+ </div>
+ <ul className="space-y-2">
+ {items.map((skill) => (
+ <li
+ key={skill}
+ className="text-sm text-muted flex items-center gap-2"
+ >
+ <span className="w-1.5 h-1.5 rounded-full bg-araucaria-500 shrink-0" />
+ {skill}
+ </li>
+ ))}
+ </ul>
+ </div>
+ ))}
+ </div>
+ </div>
+ </section>
+ </>
+ );
+}
diff --git a/src/app/(public)/articles/page.tsx b/src/app/(public)/articles/page.tsx
new file mode 100644
index 0000000..5dd7a01
--- /dev/null
+++ b/src/app/(public)/articles/page.tsx
@@ -0,0 +1,38 @@
+import { FileText } from "lucide-react";
+
+export default function ArticlesPage() {
+ return (
+ <>
+ <section className="bg-cosmos-900 py-16 sm:py-20">
+ <div className="mx-auto max-w-7xl px-6 lg:px-8">
+ <div className="mx-auto max-w-2xl text-center">
+ <h1 className="text-3xl font-bold tracking-tight text-nieve sm:text-5xl">
+ Articles & Guides
+ </h1>
+ <p className="mt-6 text-lg text-cosmos-300">
+ Concepts de sécurité, guides d&apos;implémentation OIDC/OAuth,
+ best practices Zero Trust.
+ </p>
+ </div>
+ </div>
+ </section>
+
+ <section className="py-20">
+ <div className="mx-auto max-w-7xl px-6 lg:px-8">
+ <div className="mx-auto max-w-2xl text-center">
+ <div className="w-16 h-16 mx-auto rounded-2xl bg-pewma flex items-center justify-center mb-6">
+ <FileText className="w-8 h-8 text-cosmos-500" />
+ </div>
+ <h2 className="text-xl font-semibold text-cosmos-900">
+ Articles à venir
+ </h2>
+ <p className="mt-4 text-muted">
+ Les premiers articles techniques sur OIDC, OAuth2 et le Zero Trust
+ sont en cours de rédaction. Revenez bientôt !
+ </p>
+ </div>
+ </div>
+ </section>
+ </>
+ );
+}
diff --git a/src/app/(public)/demos/page.tsx b/src/app/(public)/demos/page.tsx
new file mode 100644
index 0000000..7afee2a
--- /dev/null
+++ b/src/app/(public)/demos/page.tsx
@@ -0,0 +1,94 @@
+import Link from "next/link";
+import { Workflow, Terminal, KeyRound, ShieldCheck } from "lucide-react";
+
+const demos = [
+ {
+ icon: Workflow,
+ title: "Visualiseur OIDC",
+ description:
+ "Animation pas-à-pas des flux OIDC : Authorization Code, PKCE, Client Credentials. Comprenez chaque échange entre le client, l'IdP et le resource server.",
+ href: "/demos/oidc-flow",
+ status: "Bientôt disponible",
+ },
+ {
+ icon: Terminal,
+ title: "Playground OAuth2",
+ description:
+ "Testez interactivement les requêtes OAuth2. Explorez les scopes, tokens, refresh tokens. Connecté à un vrai serveur Keycloak.",
+ href: "/demos/oauth-playground",
+ status: "Bientôt disponible",
+ },
+ {
+ icon: KeyRound,
+ title: "Décodeur JWT",
+ description:
+ "Décodez et inspectez vos tokens JWT en temps réel. Visualisez le header, le payload et validez la signature.",
+ href: "/demos/token-decoder",
+ status: "Bientôt disponible",
+ },
+ {
+ icon: ShieldCheck,
+ title: "Simulateur Zero Trust",
+ description:
+ "Visualisation interactive des couches de sécurité Zero Trust. Explorez les différentes stratégies d'implémentation.",
+ href: "/demos/zero-trust",
+ status: "Bientôt disponible",
+ },
+];
+
+export default function DemosPage() {
+ return (
+ <>
+ <section className="bg-cosmos-900 py-16 sm:py-20">
+ <div className="mx-auto max-w-7xl px-6 lg:px-8">
+ <div className="mx-auto max-w-2xl text-center">
+ <h1 className="text-3xl font-bold tracking-tight text-nieve sm:text-5xl">
+ Démos interactives
+ </h1>
+ <p className="mt-6 text-lg text-cosmos-300">
+ Explorez les concepts de sécurité et d&apos;IAM à travers des
+ outils interactifs. Apprenez en pratiquant.
+ </p>
+ </div>
+ </div>
+ </section>
+
+ <section className="py-20">
+ <div className="mx-auto max-w-7xl px-6 lg:px-8">
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-8">
+ {demos.map((demo) => {
+ const Icon = demo.icon;
+ return (
+ <div
+ key={demo.title}
+ className="group relative rounded-xl border border-border bg-nieve p-8 hover:border-cosmos-300 hover:shadow-lg transition-all duration-300"
+ >
+ <div className="flex items-start justify-between mb-6">
+ <div className="w-12 h-12 rounded-lg bg-cosmos-900 flex items-center justify-center">
+ <Icon className="w-6 h-6 text-araucaria-400" />
+ </div>
+ <span className="px-3 py-1 text-xs font-medium bg-araucaria-50 text-araucaria-700 rounded-full border border-araucaria-200">
+ {demo.status}
+ </span>
+ </div>
+ <h3 className="text-xl font-semibold text-cosmos-900">
+ {demo.title}
+ </h3>
+ <p className="mt-3 text-sm text-muted leading-relaxed">
+ {demo.description}
+ </p>
+ <Link
+ href={demo.href}
+ className="mt-6 inline-flex items-center text-sm font-semibold text-cosmos-700 hover:text-kultrun-700 transition-colors"
+ >
+ Explorer la démo &rarr;
+ </Link>
+ </div>
+ );
+ })}
+ </div>
+ </div>
+ </section>
+ </>
+ );
+}
diff --git a/src/app/(public)/layout.tsx b/src/app/(public)/layout.tsx
new file mode 100644
index 0000000..5b71246
--- /dev/null
+++ b/src/app/(public)/layout.tsx
@@ -0,0 +1,16 @@
+import { Header } from "@/components/layout/Header";
+import { Footer } from "@/components/layout/Footer";
+
+export default function PublicLayout({
+ children,
+}: {
+ children: React.ReactNode;
+}) {
+ return (
+ <>
+ <Header />
+ <main className="min-h-[calc(100vh-4rem)]">{children}</main>
+ <Footer />
+ </>
+ );
+}
diff --git a/src/app/(public)/page.tsx b/src/app/(public)/page.tsx
new file mode 100644
index 0000000..36ecee7
--- /dev/null
+++ b/src/app/(public)/page.tsx
@@ -0,0 +1,174 @@
+import Link from "next/link";
+import {
+ Shield,
+ Key,
+ Lock,
+ Network,
+ Server,
+ ArrowRight,
+ CheckCircle,
+} from "lucide-react";
+
+const expertises = [
+ {
+ icon: Key,
+ title: "OIDC & OAuth2",
+ description:
+ "Intégration et sécurisation des flux d'authentification. Authorization Code, PKCE, Client Credentials.",
+ },
+ {
+ icon: Shield,
+ title: "Zero Trust",
+ description:
+ "Architecture Zero Trust de bout en bout. Never trust, always verify. Micro-segmentation et contrôle d'accès continu.",
+ },
+ {
+ icon: Lock,
+ title: "Active Directory & Entra ID",
+ description:
+ "Administration, durcissement et migration AD. Configuration Entra ID, Conditional Access, PIM.",
+ },
+ {
+ icon: Network,
+ title: "IAM & Gouvernance",
+ description:
+ "Stratégie IAM complète. Gestion des identités, provisioning, RBAC/ABAC, audit et conformité.",
+ },
+ {
+ icon: Server,
+ title: "Infrastructure & DevSecOps",
+ description:
+ "Sécurisation Linux & Windows. Automatisation, durcissement, monitoring sécurité.",
+ },
+];
+
+const highlights = [
+ "Expert senior avec expérience en développement, systèmes et sécurité",
+ "Maîtrise des environnements Open Source et Windows",
+ "Approche pragmatique orientée résultats",
+ "Accompagnement de la stratégie à l'implémentation",
+];
+
+export default function HomePage() {
+ return (
+ <>
+ {/* Hero */}
+ <section className="relative overflow-hidden bg-cosmos-900 py-24 sm:py-32">
+ <div className="absolute inset-0 opacity-10">
+ <div
+ className="absolute inset-0"
+ style={{
+ backgroundImage: `radial-gradient(circle at 25% 25%, var(--color-araucaria-500) 1px, transparent 1px),
+ radial-gradient(circle at 75% 75%, var(--color-kultrun-700) 1px, transparent 1px)`,
+ backgroundSize: "60px 60px",
+ }}
+ />
+ </div>
+ <div className="relative mx-auto max-w-7xl px-6 lg:px-8">
+ <div className="mx-auto max-w-3xl text-center">
+ <p className="text-sm font-semibold text-araucaria-400 uppercase tracking-widest">
+ Consulting IAM & Sécurité
+ </p>
+ <h1 className="mt-4 text-4xl font-bold tracking-tight text-nieve sm:text-6xl">
+ Sécurisez vos identités,
+ <br />
+ <span className="text-araucaria-400">protégez vos accès</span>
+ </h1>
+ <p className="mt-6 text-lg leading-8 text-cosmos-300">
+ Expert senior en Identity & Access Management. J&apos;accompagne
+ les organisations dans leur stratégie de sécurité des identités,
+ de l&apos;audit à l&apos;implémentation.
+ </p>
+ <div className="mt-10 flex items-center justify-center gap-4 flex-wrap">
+ <Link
+ href="/services"
+ className="inline-flex items-center gap-2 rounded-lg bg-kultrun-700 px-6 py-3 text-sm font-semibold text-nieve hover:bg-kultrun-600 transition-colors"
+ >
+ Mes services
+ <ArrowRight className="w-4 h-4" />
+ </Link>
+ <Link
+ href="/demos"
+ className="inline-flex items-center gap-2 rounded-lg border border-cosmos-600 px-6 py-3 text-sm font-semibold text-cosmos-200 hover:bg-cosmos-800 hover:text-nieve transition-colors"
+ >
+ Voir les démos
+ </Link>
+ </div>
+ </div>
+ </div>
+ </section>
+
+ {/* Highlights */}
+ <section className="py-12 bg-pewma border-b border-border">
+ <div className="mx-auto max-w-7xl px-6 lg:px-8">
+ <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
+ {highlights.map((text) => (
+ <div key={text} className="flex items-start gap-3">
+ <CheckCircle className="w-5 h-5 text-ngunechen-700 mt-0.5 shrink-0" />
+ <p className="text-sm text-tierra-700 font-medium">{text}</p>
+ </div>
+ ))}
+ </div>
+ </div>
+ </section>
+
+ {/* Expertises */}
+ <section className="py-20 sm:py-28">
+ <div className="mx-auto max-w-7xl px-6 lg:px-8">
+ <div className="mx-auto max-w-2xl text-center">
+ <h2 className="text-3xl font-bold tracking-tight text-cosmos-900 sm:text-4xl">
+ Domaines d&apos;expertise
+ </h2>
+ <p className="mt-4 text-lg text-muted">
+ Une expertise transversale, du développement à
+ l&apos;infrastructure, centrée sur la sécurité des identités.
+ </p>
+ </div>
+
+ <div className="mx-auto mt-16 grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-3">
+ {expertises.map((item) => {
+ const Icon = item.icon;
+ return (
+ <div
+ key={item.title}
+ className="group relative rounded-xl border border-border bg-nieve p-8 hover:border-cosmos-300 hover:shadow-lg transition-all duration-300"
+ >
+ <div className="w-12 h-12 rounded-lg bg-cosmos-900 flex items-center justify-center group-hover:bg-cosmos-800 transition-colors">
+ <Icon className="w-6 h-6 text-araucaria-400" />
+ </div>
+ <h3 className="mt-6 text-lg font-semibold text-cosmos-900">
+ {item.title}
+ </h3>
+ <p className="mt-2 text-sm text-muted leading-relaxed">
+ {item.description}
+ </p>
+ </div>
+ );
+ })}
+ </div>
+ </div>
+ </section>
+
+ {/* CTA */}
+ <section className="bg-cosmos-900 py-16">
+ <div className="mx-auto max-w-7xl px-6 lg:px-8">
+ <div className="mx-auto max-w-2xl text-center">
+ <h2 className="text-2xl font-bold text-nieve sm:text-3xl">
+ Un projet de sécurisation ?
+ </h2>
+ <p className="mt-4 text-cosmos-300">
+ Discutons de vos besoins en IAM et sécurité informatique.
+ </p>
+ <Link
+ href="/contact"
+ className="mt-8 inline-flex items-center gap-2 rounded-lg bg-araucaria-500 px-8 py-3 text-sm font-semibold text-cosmos-950 hover:bg-araucaria-400 transition-colors"
+ >
+ Prendre contact
+ <ArrowRight className="w-4 h-4" />
+ </Link>
+ </div>
+ </div>
+ </section>
+ </>
+ );
+}
diff --git a/src/app/(public)/services/page.tsx b/src/app/(public)/services/page.tsx
new file mode 100644
index 0000000..424e939
--- /dev/null
+++ b/src/app/(public)/services/page.tsx
@@ -0,0 +1,148 @@
+import {
+ Search,
+ Key,
+ ShieldCheck,
+ Server,
+ ArrowRight,
+} from "lucide-react";
+import Link from "next/link";
+
+const services = [
+ {
+ id: "audit",
+ icon: Search,
+ title: "Audit IAM & Sécurité",
+ description:
+ "Évaluation complète de votre posture de sécurité des identités. Analyse des configurations AD, Entra ID, politiques d'accès, et recommandations priorisées.",
+ deliverables: [
+ "Rapport d'audit détaillé",
+ "Matrice de risques priorisée",
+ "Plan de remédiation",
+ ],
+ },
+ {
+ id: "oidc",
+ icon: Key,
+ title: "Intégration OIDC / OAuth2",
+ description:
+ "Conception et implémentation de flux d'authentification modernes. Intégration d'applications existantes avec OIDC, migration depuis SAML, mise en place de SSO.",
+ deliverables: [
+ "Architecture d'authentification",
+ "Implémentation et tests",
+ "Documentation technique",
+ ],
+ },
+ {
+ id: "zero-trust",
+ icon: ShieldCheck,
+ title: "Stratégie Zero Trust",
+ description:
+ "Définition et déploiement d'une architecture Zero Trust adaptée à votre contexte. Conditional Access, micro-segmentation, vérification continue.",
+ deliverables: [
+ "Feuille de route Zero Trust",
+ "Configuration Conditional Access",
+ "Formation des équipes",
+ ],
+ },
+ {
+ id: "ad-entra",
+ icon: Server,
+ title: "AD & Entra ID",
+ description:
+ "Administration avancée, durcissement et migration Active Directory. Configuration Entra ID, synchronisation hybride, PIM/PAM.",
+ deliverables: [
+ "Durcissement AD (tiering model)",
+ "Configuration Entra ID",
+ "Migration et synchronisation",
+ ],
+ },
+];
+
+export default function ServicesPage() {
+ return (
+ <>
+ <section className="bg-cosmos-900 py-16 sm:py-20">
+ <div className="mx-auto max-w-7xl px-6 lg:px-8">
+ <div className="mx-auto max-w-2xl text-center">
+ <h1 className="text-3xl font-bold tracking-tight text-nieve sm:text-5xl">
+ Services de consulting
+ </h1>
+ <p className="mt-6 text-lg text-cosmos-300">
+ Des mandats ciblés pour sécuriser vos identités et vos accès,
+ de l&apos;audit stratégique à l&apos;implémentation technique.
+ </p>
+ </div>
+ </div>
+ </section>
+
+ <section className="py-20">
+ <div className="mx-auto max-w-7xl px-6 lg:px-8">
+ <div className="space-y-16">
+ {services.map((service, index) => {
+ const Icon = service.icon;
+ const isEven = index % 2 === 0;
+ return (
+ <div
+ key={service.id}
+ id={service.id}
+ className={`flex flex-col lg:flex-row gap-8 lg:gap-16 items-start ${
+ isEven ? "" : "lg:flex-row-reverse"
+ }`}
+ >
+ <div className="flex-1">
+ <div className="flex items-center gap-4 mb-4">
+ <div className="w-12 h-12 rounded-lg bg-cosmos-900 flex items-center justify-center">
+ <Icon className="w-6 h-6 text-araucaria-400" />
+ </div>
+ <h2 className="text-2xl font-bold text-cosmos-900">
+ {service.title}
+ </h2>
+ </div>
+ <p className="text-muted leading-relaxed">
+ {service.description}
+ </p>
+ </div>
+ <div className="flex-1 w-full lg:max-w-sm">
+ <div className="rounded-xl border border-border bg-pewma p-6">
+ <h3 className="text-sm font-semibold text-cosmos-700 uppercase tracking-wider mb-4">
+ Livrables
+ </h3>
+ <ul className="space-y-3">
+ {service.deliverables.map((item) => (
+ <li
+ key={item}
+ className="flex items-start gap-3 text-sm text-tierra-700"
+ >
+ <ArrowRight className="w-4 h-4 text-kultrun-700 mt-0.5 shrink-0" />
+ {item}
+ </li>
+ ))}
+ </ul>
+ </div>
+ </div>
+ </div>
+ );
+ })}
+ </div>
+ </div>
+ </section>
+
+ <section className="bg-pewma py-16 border-t border-border">
+ <div className="mx-auto max-w-7xl px-6 lg:px-8 text-center">
+ <h2 className="text-2xl font-bold text-cosmos-900">
+ Besoin d&apos;un mandat sur mesure ?
+ </h2>
+ <p className="mt-4 text-muted">
+ Chaque organisation est unique. Discutons de vos besoins spécifiques.
+ </p>
+ <Link
+ href="/contact"
+ className="mt-8 inline-flex items-center gap-2 rounded-lg bg-kultrun-700 px-8 py-3 text-sm font-semibold text-nieve hover:bg-kultrun-600 transition-colors"
+ >
+ Discuter de mon projet
+ </Link>
+ </div>
+ </section>
+ </>
+ );
+}
diff --git a/src/app/globals.css b/src/app/globals.css
new file mode 100644
index 0000000..9fa0a21
--- /dev/null
+++ b/src/app/globals.css
@@ -0,0 +1,102 @@
+@import "tailwindcss";
+
+@theme {
+ /* === Palette Mapuche Corporate === */
+
+ /* Primary - Cosmos (bleu-nuit profond) */
+ --color-cosmos-50: #e8ecf3;
+ --color-cosmos-100: #c5cfe0;
+ --color-cosmos-200: #9fafc9;
+ --color-cosmos-300: #7990b2;
+ --color-cosmos-400: #5c79a1;
+ --color-cosmos-500: #3f6290;
+ --color-cosmos-600: #355585;
+ --color-cosmos-700: #294576;
+ --color-cosmos-800: #1f3664;
+ --color-cosmos-900: #1b2a4a;
+ --color-cosmos-950: #0f1829;
+
+ /* Accent - Kultrun Red */
+ --color-kultrun-50: #fce8e8;
+ --color-kultrun-100: #f8c5c6;
+ --color-kultrun-200: #f09ea0;
+ --color-kultrun-300: #e8777a;
+ --color-kultrun-400: #e1595d;
+ --color-kultrun-500: #d93c40;
+ --color-kultrun-600: #c4343a;
+ --color-kultrun-700: #b8282e;
+ --color-kultrun-800: #9a2026;
+ --color-kultrun-900: #7a181d;
+ --color-kultrun-950: #4a0e11;
+
+ /* Secondary - Araucaria Gold */
+ --color-araucaria-50: #fbf5e6;
+ --color-araucaria-100: #f5e6c0;
+ --color-araucaria-200: #eed596;
+ --color-araucaria-300: #e7c46c;
+ --color-araucaria-400: #e1b84d;
+ --color-araucaria-500: #d4a843;
+ --color-araucaria-600: #c99a30;
+ --color-araucaria-700: #b28527;
+ --color-araucaria-800: #9a6f1f;
+ --color-araucaria-900: #7a5616;
+ --color-araucaria-950: #4a340d;
+
+ /* Earth - Tierra */
+ --color-tierra-50: #f3ede8;
+ --color-tierra-100: #e0d3c8;
+ --color-tierra-200: #ccb7a5;
+ --color-tierra-300: #b79b82;
+ --color-tierra-400: #a78568;
+ --color-tierra-500: #97704f;
+ --color-tierra-600: #886347;
+ --color-tierra-700: #6b4c3b;
+ --color-tierra-800: #573d30;
+ --color-tierra-900: #3e2b22;
+ --color-tierra-950: #241913;
+
+ /* Success - Ngünechen Green */
+ --color-ngunechen-50: #e8f2eb;
+ --color-ngunechen-100: #c5dece;
+ --color-ngunechen-200: #9ec9ae;
+ --color-ngunechen-300: #77b38e;
+ --color-ngunechen-400: #5aa375;
+ --color-ngunechen-500: #3d935c;
+ --color-ngunechen-600: #358352;
+ --color-ngunechen-700: #2d5a3d;
+ --color-ngunechen-800: #244a32;
+ --color-ngunechen-900: #1a3624;
+ --color-ngunechen-950: #0f2015;
+
+ /* Semantic surface colors */
+ --color-nieve: #faf7f2;
+ --color-pewma: #ede8df;
+ --color-border: #d4cfc6;
+ --color-muted: #7a746b;
+ --color-text: #1a1614;
+
+ /* Font families */
+ --font-sans: "Inter", ui-sans-serif, system-ui, sans-serif;
+ --font-mono: "JetBrains Mono", ui-monospace, monospace;
+
+ /* Border radius */
+ --radius-sm: 0.375rem;
+ --radius-md: 0.5rem;
+ --radius-lg: 0.75rem;
+ --radius-xl: 1rem;
+}
+
+@layer base {
+ body {
+ background-color: var(--color-nieve);
+ color: var(--color-text);
+ font-family: var(--font-sans);
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ }
+
+ ::selection {
+ background-color: var(--color-cosmos-900);
+ color: var(--color-nieve);
+ }
+}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
new file mode 100644
index 0000000..857dbf9
--- /dev/null
+++ b/src/app/layout.tsx
@@ -0,0 +1,31 @@
+import type { Metadata } from "next";
+import "./globals.css";
+
+export const metadata: Metadata = {
+ title: "Der-topogo | Consulting IAM & Sécurité",
+ description:
+ "Expert senior en Identity & Access Management, sécurité informatique, OIDC/OAuth, Zero Trust. Active Directory, Microsoft Entra ID, Open Source.",
+ keywords: [
+ "IAM",
+ "sécurité informatique",
+ "OIDC",
+ "OAuth",
+ "Zero Trust",
+ "Active Directory",
+ "Entra ID",
+ "consulting",
+ "cybersécurité",
+ ],
+};
+
+export default function RootLayout({
+ children,
+}: Readonly<{
+ children: React.ReactNode;
+}>) {
+ return (
+ <html lang="fr">
+ <body>{children}</body>
+ </html>
+ );
+}