From a21bd6a6710d123ef3bfc3c9aab37fc0c276f9c5 Mon Sep 17 00:00:00 2001 From: ertopogo Date: Thu, 19 Feb 2026 11:34:16 +0100 Subject: feat: initial project setup - Next.js 16, Payload CMS v3, palette Mapuche Next.js 16 App Router + TypeScript + Tailwind CSS v4. Payload CMS v3 with PostgreSQL adapter. Mapuche Corporate palette. Public pages, Docker Compose + Caddy, security middleware. Co-authored-by: Cursor --- .../(payload)/admin/[[...segments]]/not-found.tsx | 23 +++ src/app/(payload)/admin/[[...segments]]/page.tsx | 23 +++ src/app/(payload)/admin/importMap.js | 3 + src/app/(payload)/api/[...slug]/route.ts | 19 +++ src/app/(payload)/custom.scss | 1 + src/app/(payload)/layout.tsx | 31 ++++ src/app/(public)/about/page.tsx | 153 ++++++++++++++++++ src/app/(public)/articles/page.tsx | 38 +++++ src/app/(public)/demos/page.tsx | 94 +++++++++++ src/app/(public)/layout.tsx | 16 ++ src/app/(public)/page.tsx | 174 +++++++++++++++++++++ src/app/(public)/services/page.tsx | 148 ++++++++++++++++++ src/app/globals.css | 102 ++++++++++++ src/app/layout.tsx | 31 ++++ 14 files changed, 856 insertions(+) create mode 100644 src/app/(payload)/admin/[[...segments]]/not-found.tsx create mode 100644 src/app/(payload)/admin/[[...segments]]/page.tsx create mode 100644 src/app/(payload)/admin/importMap.js create mode 100644 src/app/(payload)/api/[...slug]/route.ts create mode 100644 src/app/(payload)/custom.scss create mode 100644 src/app/(payload)/layout.tsx create mode 100644 src/app/(public)/about/page.tsx create mode 100644 src/app/(public)/articles/page.tsx create mode 100644 src/app/(public)/demos/page.tsx create mode 100644 src/app/(public)/layout.tsx create mode 100644 src/app/(public)/page.tsx create mode 100644 src/app/(public)/services/page.tsx create mode 100644 src/app/globals.css create mode 100644 src/app/layout.tsx (limited to 'src/app') 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 => + 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 => + 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) => ( + + {children} + +); + +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 ( + <> +
+
+
+

+ À propos +

+

+ Un parcours du développement à la sécurité, pour une vision + complète et pragmatique de l'IAM. +

+
+
+
+ + {/* Timeline */} +
+
+

+ Parcours professionnel +

+
+
+
+ {timeline.map((item, index) => { + const Icon = item.icon; + const isLeft = index % 2 === 0; + return ( +
+
+

+ {item.period} +

+

+ {item.title} +

+

+ {item.description} +

+
+
+ +
+
+
+ ); + })} +
+
+
+
+ + {/* Compétences */} +
+
+

+ Compétences techniques +

+
+ {Object.entries(skills).map(([category, items]) => ( +
+
+ +

+ {category} +

+
+
    + {items.map((skill) => ( +
  • + + {skill} +
  • + ))} +
+
+ ))} +
+
+
+ + ); +} 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 ( + <> +
+
+
+

+ Articles & Guides +

+

+ Concepts de sécurité, guides d'implémentation OIDC/OAuth, + best practices Zero Trust. +

+
+
+
+ +
+
+
+
+ +
+

+ Articles à venir +

+

+ Les premiers articles techniques sur OIDC, OAuth2 et le Zero Trust + sont en cours de rédaction. Revenez bientôt ! +

+
+
+
+ + ); +} 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 ( + <> +
+
+
+

+ Démos interactives +

+

+ Explorez les concepts de sécurité et d'IAM à travers des + outils interactifs. Apprenez en pratiquant. +

+
+
+
+ +
+
+
+ {demos.map((demo) => { + const Icon = demo.icon; + return ( +
+
+
+ +
+ + {demo.status} + +
+

+ {demo.title} +

+

+ {demo.description} +

+ + Explorer la démo → + +
+ ); + })} +
+
+
+ + ); +} 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 ( + <> +
+
{children}
+