Newer
Older
geekbrain_io_web / docs / superpowers / specs / 2025-03-21-geekbrain-portfolio-design.md
# Spécification de Design: Portfolio Geekbrain.io

**Date:** 2025-03-21
**Statut:** Brouillon
**Auteur:** Claude (avec Eric Chicoine)

---

## 1. Vision et Objectifs

### 1.1 But du projet
Créer un site portfolio professionnel pour présenter les activités de développeur Python/Agentique freelance sous la marque Geekbrain.io.

### 1.2 Objectifs spécifiques
- Présenter les compétences et expériences
- Afficher les projets via une liste dynamique tirée du GitBucket local
- Permettre aux clients potentiels de contacter via un formulaire
- Design steampunk professionnel moderne
- Hébergement sur NAS Docker avec Nginx Proxy Manager
- Maintenance simple et contrôle total du code

---

## 2. Exigences

### 2.1 Exigences fonctionnelles

#### Pages
- **Accueil**: Hero section, résumé, services, compétences principales, CTA
- **À propos**: Parcours, photo, compétences détaillées
- **Projets**: Liste automatique des repos GitBucket (nom + description README)
- **Contact**: Formulaire avec validation, reCAPTCHA, envoi email + stockage BD

#### Formulaire de contact
Champs:
- Nom (obligatoire)
- Email (obligatoire, validation email)
- Sujet (obligatoire)
- Message (obligatoire)
- Soumis avec reCAPTCHA v2

Traitement:
- Validation frontend + backend
- Stockage en base de données (table `contacts`)
- Envoi email via SMTP Gmail ([email protected])
- Réponse HTTP appropriée (succès/erreur)

#### Affichage des projets
- Appel API GitBucket: `http://10.0.0.16:8080/api/v3/users/rcairbum/repos`
- Extraction: `name` + `description`
- Affichage en cartes **sans lien** vers le repo GitBucket (projets affichés en lecture seule)
- Si API down ou erreur: afficher "Projets temporairement indisponibles"
- Cache: 5 minutes
- Note: Les repos seront configurés en **public** sur GitBucket, donc pas besoin d'authentification

### 2.2 Exigences non-fonctionnelles

#### Performance
- Site rapide (FastAPI asynchrone)
- Cache des appels GitBucket (éviter requêtes fréquentes)

#### Sécurité
- reCAPTCHA pour anti-spam
- Validation backend complète
- Pas d'injection SQL (SQLAlchemy ORM)
- Variables d'environnement pour secrets (SMTP, DB)
- Headers de sécurité (CORS, etc.)

#### Hébergement
- Docker container isolé
- Utilisation MariaDB existante
- Proxy via Nginx Proxy Manager
- HTTPS automatique via Let's Encrypt

#### Maintenance
- Configuration via variables d'environnement
- Logs structurés
- Code modulaire et documenté

---

## 3. Architecture Technique

### 3.1 Stack
- **Backend:** FastAPI 0.104+ (Python 3.11+)
- **Frontend:** Jinja2 templates + CSS personnalisé
- **Base de données:** MariaDB (10.0.0.16:3306)
- **ORM:** SQLAlchemy 2.0+ avec asyncpg (async)
- **Validation:** Pydantic v2
- **Email:** aiosmtplib (async SMTP)
- **Container:** Docker + docker-compose
- **Proxy:** Nginx Proxy Manager
- **API externe:** GitBucket REST API (compatible GitHub v3)

### 3.2 Structure du projet
```
geekbrain-portfolio/
├── app/
│   ├── __init__.py
│   ├── main.py              # FastAPI app, routes
│   ├── config.py            # Configuration (env vars)
│   ├── database.py          # DB connection, session
│   ├── models.py            # SQLAlchemy models
│   ├── schemas.py           # Pydantic schemas
│   ├── crud.py              # Database operations
│   ├── routes/
│   │   ├── home.py
│   │   ├── about.py
│   │   ├── projects.py
│   │   └── contact.py
│   ├── services/
│   │   ├── gitbucket.py     # Fetch repos from GitBucket
│   │   └── email.py         # Send contact email
│   ├── templates/
│   │   ├── base.html        # Steampunk theme
│   │   ├── index.html
│   │   ├── about.html
│   │   ├── projects.html
│   │   └── contact.html
│   ├── static/
│   │   ├── css/
│   │   │   └── style.css    # Steampunk styling
│   │   ├── js/
│   │   │   └── main.js      # Frontend validation, reCAPTCHA
│   │   └── assets/          # Logo et images (copié depuis public/assets/)
│   │       └── images/      # Contient Geekbrain-io.png
└── docker/
    ├── Dockerfile
    ├── docker-compose.yml
    └── .env.example

```

### 3.3 Docker
**Dockerfile:**
```dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
```

**docker-compose.yml:**
```yaml
version: '3.8'
services:
  web:
    build: .
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=mysql+aiomysql://geekbrain_app:${DB_PASSWORD}@10.0.0.16:3306/geekbrain_portfolio
      - SMTP_HOST=${SMTP_HOST}
      - SMTP_PORT=${SMTP_PORT}
      - SMTP_USER=${SMTP_USER}
      - SMTP_PASSWORD=${SMTP_PASSWORD}
      - RECAPTCHA_SECRET=${RECAPTCHA_SECRET}
      - GITBUCKET_URL=http://10.0.0.16:8080/api/v3/users/rcairbum/repos
    volumes:
      - ./app/static:/app/static
    restart: unless-stopped
```

### 3.4 Base de données

#### Création MariaDB (à exécuter sur le serveur DB)
```sql
CREATE DATABASE geekbrain_portfolio CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

CREATE USER 'geekbrain_app'@'%' IDENTIFIED BY '${APP_DB_PASSWORD}';
GRANT SELECT, INSERT, UPDATE, DELETE ON geekbrain_portfolio.* TO 'geekbrain_app'@'%';
FLUSH PRIVILEGES;
```
*(Privilèges restreints aux opérations nécessaires, pas ALL PRIVILEGES pour plus de sécurité)*

#### Schéma
**Table `contacts`:**
```sql
CREATE TABLE contacts (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    email VARCHAR(255) NOT NULL,
    subject VARCHAR(255) NOT NULL,
    message TEXT NOT NULL,
    submitted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    ip_address VARCHAR(45),
    recaptcha_score FLOAT
);
```

(Optionnel) Table `site_settings` pour config future?

---

## 4. Modèles de données (SQLAlchemy)

### Contact
```python
class Contact(Base):
    __tablename__ = "contacts"
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column(String(255))
    email: Mapped[str] = mapped_column(String(255))
    subject: Mapped[str] = mapped_column(String(255))
    message: Mapped[str] = mapped_column(Text)
    submitted_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
    ip_address: Mapped[Optional[str]] = mapped_column(String(45))
```

---

## 5. API Endpoints (FastAPI)

| Méthode | Path | Description |
|---------|------|-------------|
| GET | `/` | Page d'accueil |
| GET | `/about` | Page à propos |
| GET | `/projects` | Page projets (appelle GitBucket API) |
| GET | `/contact` | Page contact (formulaire) |
| POST | `/contact` | Soumission formulaire (validate + save + email) |
| GET | `/health` | Health check (pour monitoring) |

### POST `/contact` body
```json
{
  "name": "Jean Dupont",
  "email": "[email protected]",
  "subject": "Demande de devis",
  "message": "Bonjour, je souhaite...",
  "recaptcha_token": "token_from_frontend"
}
```

### Response
```json
{
  "success": true,
  "message": "Message envoyé avec succès"
}
```

---

## 6. Design UI/UX

### 6.1 Palette Steampunk Pro Moderne
- **Primaire:** Laiton doré `#D4AF37` (boutons, accents)
- **Secondaire:** Gris acier `#4a4a4a` (textes secondaires, fonds sombres)
- **Fond clair:** Blanc cassé `#F5F5DC` (cartes, contenu)
- **Fond sombre:** Noir charbon `#1a1a1a` (header, footer, hero)
- **Accent:** Cuivre `#B87333` (gradients, hover)

### 6.2 Typographie
- Headers: Times New Roman, Georgia (serif)
- Body: System fonts (sans-serif pour lisibilité)
- Tailles généreuses, espacement aéré

### 6.3 Layout
- Header sombre avec logo (`public/assets/images/Geekbrain-io.png`) à gauche, nav alignée droite
- Navigation horizontale desktop, hamburger menu mobile
- Hero section avec gradient doré et call-to-action
- Grille responsive pour projets et cartes
- Footer sombre avec copyright + LinkedIn
- Bordure `2px solid #D4AF37` sur cartes/hero

### 6.4 Responsive
- Mobile-first CSS
- Breakpoints: 768px, 1024px
- Navigation adaptative

---

## 7. Configuration

Variables d'environnement requises:

| Variable | Description | obligatoire |
|----------|-------------|-------------|
| `DATABASE_URL` | Connection MariaDB (SQLAlchemy format) | Oui |
| `SMTP_HOST` | Serveur SMTP (smtp.gmail.com) | Oui |
| `SMTP_PORT` | Port SMTP (587) | Oui |
| `SMTP_USER` | Email expéditeur ([email protected]) | Oui |
| `SMTP_PASSWORD` | Mot de passe/mot de passe d'appli Gmail | Oui |
| `RECAPTCHA_SECRET` | Clé secrète reCAPTCHA v2 | Oui |
| `GITBUCKET_URL` | URL API GitBucket | Oui |
| `CACHE_TTL` | Cache API GitBucket en secondes (défaut: 300) | Non |

---

## 8. Sécurité

### 8.1 reCAPTCHA
- reCAPTCHA v2 ("I'm not a robot") sur formulaire
- Vérification backend via secret key
- Score/threshold pour détecter bots

### 8.2 Validation
- Pydantic pour schémas de données
- Validation email, longueur, caractères
- Protection CSRF? (pas nécessaire pour API simple)

### 8.3 Headers
- CORS configuré (allow origins si besoin)
- X-Content-Type-Options: nosniff
- X-Frame-Options: DENY

### 8.4 Secrets
- Variables d'environnement uniquement
- Jamais commit de .env
- Supporter configurer via Docker secrets/swarm si nécessaire

---

## 9. Intégrations externes

### 9.1 GitBucket API
- Endpoint: `http://10.0.0.16:8080/api/v3/users/rcairbum/repos`
- Méthode: GET
- Format: JSON (compatible GitHub API v3)
- Authentication: **Non requis** (les repos seront configurés en public)
- Cache: 5 minutes par défaut (pour éviter surcharge)
- Fallback: Si erreur/timeout, afficher message "Projets temporairement indisponibles"

### 9.2 Email (SMTP)
- SMTP Gmail (TLS)
- Destinataire: [email protected] (ou configurable)
- Expéditeur: même que SMTP_USER
- Template d'email simple avec infos du contact

### 9.3 reCAPTCHA
- Version v2 (checkbox)
- Site key en frontend (dans template)
- Secret key en backend (variable env)
- Vérification via API Google

---

## 10. Hébergement et Déploiement

### 10.1 Prérequis sur NAS
- Docker installé
- Docker Compose
- MariaDB accessible (10.0.0.16:3306)
- Nginx Proxy Manager (NPM) installé

### 10.2 Étapes de déploiement

1. **Configurer la base de données MariaDB** (sur le serveur DB):
```sql
CREATE DATABASE geekbrain_portfolio CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'geekbrain_app'@'%' IDENTIFIED BY 'UN_MOT_DE_PASSE_SECURISE';
GRANT ALL PRIVILEGES ON geekbrain_portfolio.* TO 'geekbrain_app'@'%';
FLUSH PRIVILEGES;
```

2. **Préparer le container Docker:**
   - Cloner/construire l'application
   - Créer `.env` à partir de `.env.example`
   - Renseigner variables (DB password, SMTP, reCAPTCHA, etc.)

3. **Démarrer le service:**
```bash
docker-compose up -d
```

4. **Configurer Nginx Proxy Manager:**
   - Ajouter un "Proxy Host"
   - Domain names: `portfolio.geekbrain.io`
   - Scheme: http, Host: IP_DU_NAS, Port: 8000
   - Activer SSL (Let's Encrypt)
   - Activer WebSockets si besoin (pas nécessaire ici)

5. **Vérifier:**
   - Site accessible via https://portfolio.geekbrain.io
   - Formulaire fonctionne, emails reçus
   - Projets s'affichent depuis GitBucket

### 10.3 Mise à jour
```bash
git pull <repo>
docker-compose down
docker-compose up -d --build
```

---

## 11. Maintenance et Monitoring

### 11.1 Logs
- FastAPI logs structurés (JSON si possible)
- Docker logs (`docker-compose logs -f web`)
- Configuration niveau log via variable env (`LOG_LEVEL`)

### 11.2 Health check
Endpoint `/health` retourne 200 si DB connectée.

### 11.3 Sauvegardes
- Backup MariaDB automatique (géré au niveau NAS)
- Backup code Git (hors périmètre)

### 11.4 Monitoring
- Métriques FastAPI (optionnel)
- Monitoring Docker via Portainer ou Watchtower

---

## 12. Évolution future (backlog)

- Interface admin pour gérer projets (au lieu de GitBucket API)
- Blog technique avec articles markdown
- Multilanguage (i18n)
- Stats de visites (Plausible/Umami)
- Notification Slack/Discord pour nouveaux contacts
- Export contacts CSV
- Thème sombre/clair

---

## 13. Risques et Contraintes

### 13.1 Risques
- GitBucket API non accessible depuis container (réseau) → utiliser SSHFS ou API publique?
- Spam malgré reCAPTCHA → prévoir rate limiting
- SMTP Gmail limitations (quotas) → prévoir alternative
- dépendandance à GitBucket privé → considérer copie locale

### 13.2 Contraintes
- Doit fonctionner sur NAS avec ressources limitées (RAM/CPU)
- Version MariaDB existante (compatibilité SQLAlchemy)
- Accès réseau local à GitBucket (10.0.0.16)

---

## 14. Tests

### 14.1 Tests unitaires
- Modèles Pydantic
- Fonctions de validation
- Crud opérations

### 14.2 Tests d'intégration
- Endpoints API (TestClient)
- Connexion DB
- Envoi email (mock SMTP)

### 14.3 Tests manuels
- Formulaire soumission avec/erreurs
- Affichage projets (mocked API)
- Responsive design

---

## 15. Suivi et Acceptation

### Critères d'acceptation
- [ ] Site visible sur portfolio.geekbrain.io avec HTTPS
- [ ] Pages Accueil, À propos, Projets, Contact fonctionnelles
- [ ] Formulaire envoie email + stocke en BD
- [ ] reCAPTCHA fonctionnel (pas de spam)
- [ ] Liste projets dynamique depuis GitBucket
- [ ] Design steampunk pro (validé)
- [ ] Responsive mobile/desktop
- [ ] Dockerisé, logs, health check
- [ ] Variables d'env configurées
- [ ] Code documenté, structure claire

---

**Prochaines étapes:**
1. Valider cette spécification
2. Créer le plan d'implémentation détaillé (writing-plans)
3. Implémenter par phases (setup, DB, routes, templates, intégrations, Docker)
4. Tester et déployer

---

*Document generated by Claude Code - superpowers:brainstorming*