chore init
This commit is contained in:
1 parent
1b7406b1d3
commit
a0d312a884
60 files changed
+5046
-125
No files matched your search
@@ -1,36 +1,245 @@
|
||||
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
|
||||
# CV-Maker — Documentation technique
|
||||
|
||||
## Getting Started
|
||||
Application web de création de CV en temps réel : saisie **Markdown** dans un panneau latéral, **preview A4** instantanée, sauvegarde locale automatique et export **PDF** — le tout sans backend, 100 % côté navigateur.
|
||||
|
||||
First, run the development server:
|
||||
## Sommaire
|
||||
|
||||
1. [Prérequis](#prérequis)
|
||||
2. [Installation et lancement](#installation-et-lancement)
|
||||
3. [Scripts](#scripts)
|
||||
4. [Stack technique](#stack-technique)
|
||||
5. [Structure du projet](#structure-du-projet)
|
||||
6. [Modèle de données](#modèle-de-données)
|
||||
7. [Fonctionnement clé](#fonctionnement-clé)
|
||||
- [Rendu Markdown sécurisé](#rendu-markdown-sécurisé)
|
||||
- [Persistance locale](#persistance-locale)
|
||||
- [Gestion des expériences](#gestion-des-expériences)
|
||||
- [Impression PDF](#impression-pdf)
|
||||
- [PWA](#pwa)
|
||||
8. [Conception détaillée](#conception-détaillée)
|
||||
9. [Limitations connues](#limitations-connues)
|
||||
|
||||
---
|
||||
|
||||
## Prérequis
|
||||
|
||||
| Outil | Version minimale |
|
||||
| --- | --- |
|
||||
| Node.js | 20.9+ |
|
||||
| pnpm | 12.x (`corepack enable` puis `pnpm -v` — figé via `packageManager`) |
|
||||
|
||||
## Installation et lancement
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
# or
|
||||
yarn dev
|
||||
# or
|
||||
pnpm dev
|
||||
# or
|
||||
bun dev
|
||||
# 1. Installer les dépendances
|
||||
pnpm install
|
||||
|
||||
# 2. Lancer en développement
|
||||
pnpm dev # → http://localhost:3000
|
||||
|
||||
# 3. Construire + servir en production
|
||||
pnpm build
|
||||
pnpm start
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
## Scripts
|
||||
|
||||
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
||||
| Script | Commande | Description |
|
||||
| --- | --- | --- |
|
||||
| `dev` | `pnpm dev` | Serveur de développement (Turbopack) |
|
||||
| `dev:sw` | `concurrently …` | Dev + re-build du service worker en continu (`--watch`) |
|
||||
| `build` | `next build && serwist build` | Build de production + génération du service worker |
|
||||
| `start` | `pnpm start` | Lancement du build de production |
|
||||
| `lint` | `pnpm lint` | Vérification ESLint (Next.js) |
|
||||
| `typecheck` | `tsc --noEmit` | Validation TypeScript strict |
|
||||
|
||||
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
|
||||
## Stack technique
|
||||
|
||||
## Learn More
|
||||
| Brique | Choix | Rôle |
|
||||
| --- | --- | --- |
|
||||
| Framework | Next.js (App Router) | Routage, composants serveur/client, métadonnées |
|
||||
| Langage | TypeScript (strict) | Typage du modèle de données |
|
||||
| Styles | Tailwind CSS | Design tokens, responsive, print |
|
||||
| Markdown | `marked` | Conversion Markdown → HTML |
|
||||
| Sécurité | `dompurify` | Assainissement du HTML avant injection (anti-XSS) |
|
||||
| Persistance | `localStorage` | Données locales, aucune transmission |
|
||||
| PWA | `@serwist/next` + `@serwist/cli` | Service worker (mode configurator), manifest, installabilité |
|
||||
| Icônes | `lucide-react` | Iconographie |
|
||||
| Conteneurisation | Docker (multi-stage) | Image de production, distribution Docker Hub |
|
||||
|
||||
To learn more about Next.js, take a look at the following resources:
|
||||
## Structure du projet
|
||||
|
||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||
```
|
||||
cv-maker/
|
||||
├── app/
|
||||
│ ├── layout.tsx # Layout racine (lang, meta, manifest)
|
||||
│ ├── page.tsx # Éditeur principal
|
||||
│ ├── globals.css # Tokens Tailwind + @media print
|
||||
│ ├── documentation/
|
||||
│ │ └── page.tsx # Page d'aide (statique)
|
||||
│ ├── mentions-legales/
|
||||
│ │ └── page.tsx # Page Mentions légales (statique)
|
||||
│ └── sw.ts # Source du service worker (Serwist)
|
||||
├── components/
|
||||
│ ├── ui/ # Primitives réutilisables
|
||||
│ │ ├── Button.tsx
|
||||
│ │ ├── IconButton.tsx
|
||||
│ │ ├── Textarea.tsx
|
||||
│ │ ├── Tabs.tsx
|
||||
│ │ └── Footer.tsx # Pied de page (lien Mentions légales)
|
||||
│ └── cv/ # Composants métier du CV
|
||||
│ ├── CvWorkspace.tsx # Assemblage 2 colonnes + toolbar
|
||||
│ ├── CvToolbar.tsx # Barre d'app (PDF, JSON, liens)
|
||||
│ ├── CvInputPanel.tsx # Panneau gauche (tabs + expériences)
|
||||
│ ├── CvTabs.tsx # Onglets 1..5
|
||||
│ ├── MarkdownTextarea.tsx # Textarea contrôlé
|
||||
│ ├── ExperienceManager.tsx # Formulaire + liste expériences
|
||||
│ ├── ExperienceItem.tsx # Ligne « n. titre [Modifier] [×] »
|
||||
│ ├── CvPreview.tsx # Feuille A4
|
||||
│ ├── CvHeader.tsx # Accroche (zone 1)
|
||||
│ ├── CvLeftColumn.tsx # Sections 2→5 (1/3)
|
||||
│ ├── CvSection.tsx # Section générique
|
||||
│ ├── CvRightColumn.tsx # Expériences pro (2/3)
|
||||
│ └── CvExperiencePreview.tsx
|
||||
├── lib/
|
||||
│ ├── types/cv.ts # Contracts du domaine
|
||||
│ ├── markdown.ts # markdownToHtml (marked + DOMPurify)
|
||||
│ ├── storage.ts # Adapter localStorage
|
||||
│ └── hooks/
|
||||
│ ├── useLocalStorage.ts # Persistance générique
|
||||
│ └── useCVData.ts # Façade métier d'édition
|
||||
├── public/
|
||||
│ ├── manifest.webmanifest # Manifest PWA
|
||||
│ └── icons/ # icônes 192 / 512
|
||||
├── Dockerfile # Image multi-stage (deps/builder/runner)
|
||||
├── docker-compose.yml # Service cv-maker, healthcheck
|
||||
├── .dockerignore # Exclusions de contexte build
|
||||
├── serwist.config.mjs # Config service worker (mode configurator)
|
||||
├── next.config.ts # output: "standalone"
|
||||
├── tsconfig.json # strict
|
||||
├── GOAL.md # Cahier des charges source
|
||||
└── README.md # Ce document
|
||||
```
|
||||
|
||||
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
|
||||
## Modèle de données
|
||||
|
||||
## Deploy on Vercel
|
||||
Contenu stocké dans **une seule clé localStorage** : `cv-maker:v1` (JSON).
|
||||
|
||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||
```ts
|
||||
interface CVCareerData {
|
||||
version: 1;
|
||||
accroche: string; // onglet 1 — message d'accroche
|
||||
etatCivil: string; // onglet 2 — état civil + contacts + site + GitHub
|
||||
formations: string; // onglet 3 — formations
|
||||
softSkills: string; // onglet 4 — soft skills
|
||||
centresInteret: string; // onglet 5 — centres d'intérêt
|
||||
experiences: Experience[];
|
||||
}
|
||||
|
||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
||||
interface Experience {
|
||||
id: string; // crypto.randomUUID() — identifiant stable
|
||||
titre: string; // titre affiché (liste + section CV)
|
||||
contenu: string; // corps en Markdown
|
||||
createdAt: number;
|
||||
updatedAt: number;
|
||||
}
|
||||
```
|
||||
|
||||
- Les 5 zones sont du **Markdown brut** (le HTML rendu n'est jamais stocké).
|
||||
- Les expériences sont affichées **dans l'ordre de saisie** : la 1ʳᵉ ajoutée en haut de la section « Expériences professionnelles », la suivante en dessous, etc. (la 1ʳᵉ porte le numéro 1).
|
||||
- Sauvegarde invalide/corrompue → état par défaut, sans crash.
|
||||
|
||||
## Fonctionnement clé
|
||||
|
||||
### Rendu Markdown sécurisé
|
||||
|
||||
`lib/markdown.ts` — toute injection HTML passe par ici :
|
||||
|
||||
```ts
|
||||
const rawHtml = marked.parse(source, { async: false }) as string;
|
||||
return DOMPurify.sanitize(rawHtml);
|
||||
```
|
||||
|
||||
`marked` génère le HTML ; **`DOMPurify` neutralise** tout script/événement URL dangereuse avant le `dangerouslySetInnerHTML`. Aucun HTML brut saisi n'est injecté directement.
|
||||
|
||||
### Persistance locale
|
||||
|
||||
`useLocalStorage` synchronise l'état React avec localStorage **à chaque changement** (via `useEffect`) ; l'enregistrement est silencieux (aucun indicateur affiché). `useCVData` expose la façade d'édition (`setText`, `addExperience`, `updateExperience`, `removeExperience`, `resetCV`, `importCV`), et la barre d'application permet l'**export/import JSON** (`cv-maker.json`) pour partager un CV entre appareils.
|
||||
|
||||
### Gestion des expériences
|
||||
|
||||
- Bouton **+** : nouvelle expérience (formulaire titre + contenu).
|
||||
- Liste numérotée avec **Modifier** / **×** (suppression confirmée).
|
||||
- Identifiants UUID : jamais d'index comme identifiant (robustesse lors des suppressions).
|
||||
|
||||
### Impression PDF
|
||||
|
||||
- Bouton « Imprimer / PDF » → `window.print()`.
|
||||
- CSS `@media print` dans `app/globals.css` : `@page { size: A4; margin: 0 }`, panneau de saisie et toolbar masqués, seule la feuille A4 est imprimée.
|
||||
|
||||
### PWA
|
||||
|
||||
- **Mode « configurator »** (`@serwist/next` + `@serwist/cli`, compatible Turbopack) : `serwist.config.mjs` décrit le service worker, compilé par `pnpm build` après Next.js (`next build && serwist build`).
|
||||
- `public/sw.js` pré-cache les routes `/`, `/documentation`, `/mentions-legales` et tous les assets (787 kB, 20 URL).
|
||||
- En développement le service worker est **désactivé** (`SerwistProvider disable`) ; utiliser `pnpm dev:sw` pour le reconstruire à chaud.
|
||||
- `public/manifest.webmanifest` + icônes 192/512 → installable, fonctionne hors-ligne (les données du CV restent dans localStorage).
|
||||
|
||||
### Dockerisation
|
||||
|
||||
L'image est construite en **3 étapes** (`Dockerfile` multi-stage) :
|
||||
|
||||
| Étape | Image | Contenu |
|
||||
| --- | --- | --- |
|
||||
| `deps` | `node:20-alpine` | Installation déterministe des dépendances (`pnpm install --frozen-lockfile`, incl. `pnpm-workspace.yaml`) |
|
||||
| `builder` | `node:20-alpine` | Compilation (`pnpm build`, sortie `standalone` + `sw.js`) |
|
||||
| `runner` | `node:20-alpine` | Exécution uniquement (`node server.js`, image ≈ 60 Mo) |
|
||||
|
||||
**Build et lancement :**
|
||||
|
||||
```bash
|
||||
docker build -t cv-maker:latest .
|
||||
docker run --rm -p 3001:3000 cv-maker:latest # → http://localhost:3001
|
||||
```
|
||||
|
||||
> Si le port 3000 est déjà occupé en local, mapper un autre port hôte (`-p 3001:3000`).
|
||||
|
||||
**Avec Docker Compose :**
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
docker compose down
|
||||
```
|
||||
|
||||
**Publication sur Docker Hub :**
|
||||
|
||||
```bash
|
||||
docker login
|
||||
docker tag cv-maker:latest <mon-user-dockerhub>/cv-maker:latest
|
||||
docker push <mon-user-dockerhub>/cv-maker:latest
|
||||
```
|
||||
|
||||
Voir la [documentation détaillée Docker](./docs/conception/08-deploiement-docker.md) pour le contenu complet des fichiers (`Dockerfile`, `docker-compose.yml`, `.dockerignore`) et la recette de validation.
|
||||
|
||||
## Conception détaillée
|
||||
|
||||
Le dossier de conception complet (analyse fonctionnelle, architecture, modèle de données, UI, plan de réalisation pas-à-pas, sécurité/RGPD, plan de tests) se trouve dans :
|
||||
|
||||
```
|
||||
docs/conception/
|
||||
├── README.md → sommaire et ordre de lecture
|
||||
├── 01-analyse-fonctionnelle.md
|
||||
├── 02-architecture-technique.md
|
||||
├── 03-modele-donnees.md
|
||||
├── 04-specifications-ui.md
|
||||
├── 05-etapes-realisation.md
|
||||
├── 06-securite-rgpd.md
|
||||
├── 07-plan-tests.md
|
||||
└── 08-deploiement-docker.md
|
||||
```
|
||||
|
||||
## Limitations connues
|
||||
|
||||
- **Desktop first** : tablette/mobile = niveau « utilisable », non optimisé.
|
||||
- **One page A4 à l'impression** : feuille de preview à hauteur flexible ; un contenu très long peut générer plusieurs pages PDF.
|
||||
- **Pas de tests automatisés** (v1) : recette manuelle documentée dans `docs/conception/07-plan-tests.md` ; tests Vitest prévus en v2.
|
||||
- **Pas de drag & drop** de réorganisation des expériences (évolution prévue).
|
||||
Reference in new issue
Block a user