# REBOURS — Documentation technique ## Architecture du projet ``` rebours/ ├── nextjs/ # App live (Next.js 15 + Payload CMS 3 + Postgres) │ ├── src/ │ │ ├── app/ │ │ │ ├── (frontend)/ # Site public (/, /collection/[slug], /success) │ │ │ └── (payload)/admin/ # Back-office Payload (/admin) │ │ ├── collections/ # Schémas Payload (Products, Media, Users) │ │ ├── components/admin/ # Custom admin UI (visual product editor) │ │ ├── lib/payload.ts # Helpers Payload (mediaUrl, mediaAlt) │ │ ├── scripts/main.js # JS client (cursor CAD, grid, panel, carousel) │ │ ├── payload.config.ts # Config Payload (collections, plugins, drafts) │ │ └── migrations/ # Migrations Postgres (auto-générées) │ ├── public/ │ │ ├── style.css # CSS global du site public │ │ └── assets/ # Favicons, son ambiant, fallback images │ ├── Dockerfile # Image Docker unique (build + runtime) │ ├── next.config.mjs │ └── package.json ├── k8s/ # Manifests K3s (namespace, configmap, service, deployment, postgres) ├── .gitea/workflows/deploy.yml # CI/CD : build Docker + déploiement K3s └── CLAUDE.md ``` ## Stack | Couche | Techno | |--------|--------| | Front + Back | Next.js 15 (App Router, SSR) | | CMS | Payload 3 (self-hosted, monté sur `/admin`) | | Base de données | PostgreSQL (StatefulSet K3s) | | Paiement | Stripe Checkout (`price_data` inline) + plugin-stripe | | Images | Payload Media → stockage local + `sharp` | | Hébergement | K3s sur Proxmox (Traefik en front) | | Fonts | Space Mono (Google Fonts) | --- ## Développement local ### Prérequis - Node.js >= 20 - pnpm - Docker (pour Postgres local) ou une instance Postgres accessible - Un fichier `nextjs/.env` (voir `nextjs/.env.example`) ### Variables d'environnement (`nextjs/.env`) ```env DATABASE_URI=postgres://rebours:rebours@localhost:5432/rebours PAYLOAD_SECRET=your_32_char_secret STRIPE_SECRET_KEY=sk_test_... STRIPE_WEBHOOK_SECRET=whsec_... NEXT_PUBLIC_SERVER_URL=http://localhost:3000 ``` ### Lancer le projet ```bash cd nextjs pnpm install pnpm dev ``` - Site public : http://localhost:3000 - Admin Payload : http://localhost:3000/admin ### Build ```bash cd nextjs && pnpm build ``` --- ## CMS — Payload ### Accès - Admin : https://rebours.studio/admin (prod) / http://localhost:3000/admin (dev) - Premier démarrage : la page `/admin/create-first-user` demande la création du premier user. ### Collection `products` Éditeur visuel sur-mesure (`src/components/admin/ProductPreviewEditor.tsx`) : la page d'édition reproduit exactement le panneau produit public. Tous les champs éditables au clic (texte inline, carousel d'images, prix). Drawer « Réglages avancés » en bas pour les champs techniques (slug, SEO, Stripe ID). Champs principaux : `productDisplayName`, `name`, `slug`, `index`, `type`, `materials`, `year`, `status`, `description`, `specs`, `notes`, `images[]` (array d'uploads), `price` (centimes), `currency`, `availability`, `isPublished`, `seoTitle`, `seoDescription`. Autosave activé (interval 800 ms) via `versions.drafts.autosave`. ### Sync Stripe Le plugin `@payloadcms/plugin-stripe` synchronise automatiquement les produits et prix avec Stripe dès que `STRIPE_SECRET_KEY` est valide. Un hook `beforeValidate` court-circuite la sync tant que `productDisplayName` est vide (évite l'erreur Stripe sur autosave de doc neuf). --- ## Stripe ### Checkout 1. Le front envoie le slug du produit à `/api/checkout` 2. Le serveur fetch le produit via Payload Local API 3. Création d'une session Stripe avec `price_data` inline 4. Redirect vers Stripe 5. Retour : `/success?session_id=...` ### Endpoints | Route | Méthode | Description | |-------|---------|-------------| | `/api/checkout` | POST | Crée une session Stripe Checkout | | `/api/session/[id]` | GET | Statut d'une session | | `/api/stripe/webhook` | POST | Webhook Stripe (plugin-stripe) | Webhook prod : `https://rebours.studio/api/stripe/webhook` --- ## Production ### Architecture K3s ``` Internet :443 → Traefik (10.10.10.2) → Service rebours-web → Pod rebours-web :3000 ↘ Service rebours-postgres :5432 ``` ### Pods (namespace `rebours`) | Workload | Port | Rôle | |----------|------|------| | `rebours-web` (Deployment) | 3000 | Next.js + Payload (tout-en-un) | | `rebours-postgres` (StatefulSet) | 5432 | Postgres + PVC | ### Variables d'environnement en prod - **ConfigMap** (`k8s/configmap.yml`) : `NEXT_PUBLIC_SERVER_URL`, `DATABASE_URI` - **Secret `rebours-db-secret`** : `POSTGRES_DB`, `POSTGRES_USER`, `POSTGRES_PASSWORD` - **Secret `rebours-app-secret`** : `PAYLOAD_SECRET`, `STRIPE_SECRET_KEY`, `STRIPE_WEBHOOK_SECRET` - **Secret `gitea-registry-secret`** : pull de l'image depuis le registre Gitea Les secrets d'app sont créés par la CI depuis les Gitea Actions secrets. ### Déploiement Push sur `main` → Gitea Actions build l'image Docker puis applique les manifests K3s. ```bash git push gitea main ``` Repo Gitea : `https://git.arthurbarre.fr/ordinarthur/rebours` ### Debugging prod ```bash # Pods ssh arthur@100.78.207.119 "sudo kubectl -n rebours get pods" # Logs ssh arthur@100.78.207.119 "sudo kubectl -n rebours logs deployment/rebours-web --tail=50" # Redémarrer ssh arthur@100.78.207.119 "sudo kubectl -n rebours rollout restart deployment/rebours-web" # Shell Postgres ssh arthur@100.78.207.119 "sudo kubectl -n rebours exec -it rebours-postgres-0 -- psql -U rebours" ``` --- ## Routing | URL | Comportement | |-----|-------------| | `/` | Page principale (SSR, Payload Local API) | | `/collection/[slug]` | Page produit (SSR), auto-open panel via `window.__OPEN_PANEL__` | | `/success?session_id=...` | Confirmation Stripe | | `/admin` | Back-office Payload | | `/api/*` | Routes Payload (REST + GraphQL) + endpoints custom (checkout, webhook) | --- ## Fichiers à ne jamais versionner - `nextjs/.env` - `node_modules/` - `nextjs/.next/`