freedge/README.md
ordinarthur 0134390f5e refactor: cleanup, security hardening & frontend dedup
Backend:
- Remove malicious crypto dep; use node:crypto
- Add helmet + rate-limit (100 req/min)
- CORS whitelist via CORS_ORIGINS env
- Validate required env vars on boot (fail fast)
- Health endpoint + clean shutdown (SIGINT/SIGTERM)
- Multipart limits (15MB / 1 file)
- Fix findUnique composite where bug (use findFirst)
- Wrap JSON.parse(generatedRecipe) in try/catch
- Isolate DALL-E best-effort; ENABLE_IMAGE_GENERATION toggle
- Lazy MinIO client, safe TLS handling
- Uniform fastify.hashPassword/comparePassword
- Proper audio cleanup on delete
- ESLint flat config, Prettier, .env.example, .editorconfig

Frontend:
- Delete 10 orphan/duplicate components
- Remove orphan pages/recipe/, data/recipes.ts, root src/
- Fix /reset-password route order (was unreachable)
- Remove unused ky dep

Docs:
- README rewritten to match real routes and env vars

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 21:00:54 +02:00

118 lines
4.2 KiB
Markdown

# Freedge
Freedge génère des recettes personnalisées à partir des ingrédients dictés à l'oral. Le son est transcrit (Whisper), une recette est générée (GPT-4o-mini) et une image optionnelle est produite (DALL-E 3).
## Stack
- **Frontend** : React 19 + Vite + TailwindCSS + ShadCN/UI + React Router
- **Backend** : Fastify 4 + Prisma 5 + SQLite
- **IA** : OpenAI (Whisper, GPT-4o-mini, DALL-E 3)
- **Stockage** : MinIO (S3-compatible) avec fallback local
- **Paiement** : Stripe (client créé à l'inscription — intégration abonnement à finaliser)
- **Auth** : JWT + Google OAuth
## Structure
```
freedge/
├── backend/
│ ├── prisma/ # Schéma + migrations SQLite
│ └── src/
│ ├── plugins/ # auth, ai, stripe, google-auth
│ ├── routes/ # auth, recipes, users
│ ├── utils/ # env, storage (MinIO), email, resend
│ └── server.js
└── frontend/
└── src/
├── api/ # Clients HTTP (auth, user, recipe)
├── components/ # UI shadcn + composants métier
├── hooks/ # useAuth, useMobile, useAudioRecorder
├── layouts/ # MainLayout
└── pages/ # Home, Auth/*, Recipes/*, Profile, ResetPassword
```
## Prérequis
- Node.js ≥ 18
- pnpm (recommandé) ou npm
- Une clé API OpenAI
- (Optionnel) Un serveur MinIO pour le stockage images/audio
- (Optionnel) Un compte Resend pour les emails
## Démarrage
```bash
# Installation
cd backend && npm install
cd ../frontend && pnpm install
# Variables d'environnement backend (.env dans backend/)
cp .env.example .env # puis éditer
# Requis : DATABASE_URL, JWT_SECRET, OPENAI_API_KEY
# Base de données
cd backend
npx prisma migrate dev
npx prisma generate
# Lancement
npm run dev # backend sur :3000
cd ../frontend && pnpm dev # frontend sur :5173
```
## Variables d'environnement backend
| Variable | Requis | Description |
|---|---|---|
| `DATABASE_URL` | ✅ | URL Prisma (ex: `file:./prisma/dev.db`) |
| `JWT_SECRET` | ✅ | Clé JWT (≥ 32 caractères recommandé) |
| `OPENAI_API_KEY` | ✅ | Clé API OpenAI |
| `PORT` | ❌ | Port du serveur (défaut 3000) |
| `CORS_ORIGINS` | ❌ | Origines autorisées, séparées par virgule |
| `FRONTEND_URL` | ❌ | URL frontend pour les emails de reset |
| `ENABLE_IMAGE_GENERATION` | ❌ | `false` pour désactiver DALL-E |
| `OPENAI_TEXT_MODEL` | ❌ | Défaut `gpt-4o-mini` |
| `STRIPE_SECRET_KEY` | ❌ | Clé Stripe (pour créer les customers) |
| `MINIO_ENDPOINT` / `MINIO_PORT` / `MINIO_USE_SSL` / `MINIO_ACCESS_KEY` / `MINIO_SECRET_KEY` / `MINIO_BUCKET` | ❌ | Config MinIO ; fallback local sinon |
| `MINIO_ALLOW_SELF_SIGNED` | ❌ | `true` pour autoriser TLS auto-signé (DEV uniquement) |
| `RESEND_API_KEY` | ❌ | Clé Resend pour les emails |
## Routes API (préfixe `/`)
### Auth (`/auth`)
- `POST /auth/register` — Inscription email + mot de passe
- `POST /auth/login` — Connexion
- `POST /auth/google-auth` — Connexion/inscription via Google OAuth
### Utilisateurs (`/users`)
- `GET /users/profile` — Profil courant (🔒)
- `PUT /users/profile` — Mise à jour du nom (🔒)
- `PUT /users/change-password` — Changement de mot de passe (🔒)
- `PUT /users/change-email` — Changement d'email (🔒)
- `POST /users/forgot-password` — Demande de réinitialisation
- `POST /users/reset-password` — Réinitialisation avec token
- `DELETE /users/account` — Suppression du compte (🔒)
### Recettes (`/recipes`) — toutes 🔒
- `POST /recipes/create` — Upload audio + transcription + génération
- `GET /recipes/list` — Liste les recettes de l'utilisateur
- `GET /recipes/:id` — Détail d'une recette
- `DELETE /recipes/:id` — Supprime une recette
### Divers
- `GET /health` — Healthcheck
🔒 = nécessite un JWT `Authorization: Bearer <token>`
## Sécurité
- Helmet + rate-limit (100 req/min) activés
- CORS whitelisté via `CORS_ORIGINS`
- JWT signé, expiration 7 jours
- Bcrypt (10 rounds) pour les mots de passe
- Validation des variables d'environnement au démarrage
## Licence
MIT